import java.util.*;

public class Parser {


    private Map<Symbol,Map<Symbol,Set<Rule>>> predTable; 
    private Grammar gram; 

    public static void main(String[] args) {
        TableGenerator tGen = new TableGenerator(args[0]);
        System.out.println(tGen.getGrammar());
        Parser par = new Parser(tGen.getGrammar(), tGen.getTable());
        par.doAParse();
    }

    public Parser(Grammar gram,
                  Map<Symbol,Map<Symbol,Set<Rule>>> predTable) {
        this.predTable = predTable;
        this.gram = gram;
    }

    public void doAParse() {
        Scanner scan = new Scanner(System.in);
        System.out.println("Enter input to parse; use $ at end.");
        String token;
        List<Symbol> input = new ArrayList<Symbol>();
        
        while ( !(token=scan.next()).equals("$")) {
            input.add(new Symbol(token));    
        }
        input.add(Symbol.EOF);
        
        Stack<Symbol> stack = new Stack<Symbol>();
        stack.push(Symbol.EOF);
        stack.push(gram.startSymbol());
        
        while (true) {
        
            Symbol topSym = stack.pop();
            Symbol nextInput = input.get(0);
            
            if (topSym.equals(Symbol.EOF)) {
            
                if (nextInput.equals(Symbol.EOF)) 
                    System.out.println("Parse Successfully Completes");
                else 
                    System.out.println("Parse Fails");
                return;
            }
            
            if (topSym.isTerm()) {
            
                if (topSym.equals(nextInput)) {
                    input.remove(0);
                } else {
                    System.out.println("Parse Mismatch: Stack = "+topSym+" input = "+nextInput);
                    return;
                }
              
            } else {
                
                Set<Rule> rules = predTable.get(topSym).get(nextInput);
                Rule r = rules.iterator().next();  // should only be one
                System.out.println("Using rule: "+r);
                
                if (r.isNullRule()) {
                    // nothing to push onto stack
                
                } else {
                    List<Symbol> rhs = r.rhs();
                    // load up the stack backwards
                    for (int i = rhs.size()-1; i >= 0; i--) {
                        stack.push( rhs.get(i) );
                    }
                }
            
            } 
            
        }
        
    }

}